package com.capinfo.commons.project.service.security.impl;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.security.authentication.encoding.Md5PasswordEncoder;

import com.capinfo.commons.project.Constants;
import com.capinfo.commons.project.model.region.Region;
import com.capinfo.commons.project.model.security.SystemRole;
import com.capinfo.commons.project.model.security.SystemUser;
import com.capinfo.commons.project.parameter.security.SystemUserParameter;
import com.capinfo.commons.project.service.security.SystemUserService;
import com.capinfo.framework.dao.SearchCriteria.OrderRow;
import com.capinfo.framework.dao.SearchCriteria.ScopeRestriction;
import com.capinfo.framework.dao.SearchCriteriaBuilder;
import com.capinfo.framework.dao.impl.restriction.RestrictionExpression;
import com.capinfo.framework.exception.ObjectNotFoundException;
import com.capinfo.framework.service.impl.CommonsDataOperationServiceImpl;

public class SystemUserServiceImpl extends CommonsDataOperationServiceImpl<SystemUser, SystemUserParameter> implements SystemUserService {

	private static final Log logger = LogFactory.getLog(SystemUserService.class);
	
	public SearchCriteriaBuilder<SystemUser> getSearchCriteriaBuilder(SystemUserParameter parameter) {
		SearchCriteriaBuilder<SystemUser> searchCriteriaBuilder = super.getSearchCriteriaBuilder(parameter);

		searchCriteriaBuilder.setScopeRestriction(new ScopeRestriction(Region.class, parameter.getEntity().getRegionId().toString()));
		SystemUser user = parameter.getEntity();
		searchCriteriaBuilder.addQueryCondition("name", RestrictionExpression.LIKE_OP, user.getName());
		searchCriteriaBuilder.addQueryCondition("logonName", RestrictionExpression.LIKE_OP, user.getLogonName());
	
		//角色
		if(null != parameter.getRoleIds() && parameter.getRoleIds().length > 0){
			String inRoleStr = org.springframework.util.StringUtils.arrayToDelimitedString(parameter.getRoleIds(), ",");
			searchCriteriaBuilder.addAdditionalRestrictionSql("ID in (select USER_ID from SYSTEM_USERS_ROLES where ROLE_ID in(" + inRoleStr +"))");
		}
		
		searchCriteriaBuilder.addOrderCondition("id", OrderRow.ORDER_DESC);

		return searchCriteriaBuilder;
	}
	

	public SystemUser getSystemUserById(Long id) {
		
		try {
			
			return getGeneralService().getObjectById(SystemUser.class, id);
		} catch (Exception ex) {
			
			return null;
		}
	}

	
	public boolean modifyPassword(SystemUserParameter parameter) {
		
		return modifyUserPassword(parameter)!=null;
	}
	
	protected SystemUser modifyUserPassword(SystemUserParameter parameter){
		
		try {
			
			SystemUser entity = parameter.getEntity();
			SystemUser user = this.getSystemUserById(entity.getId());
			
			Md5PasswordEncoder md5 = new Md5PasswordEncoder();
			if( null != parameter.getOriginalPassword() ){
				if( !user.getPassword().equals(md5.encodePassword(parameter.getOriginalPassword(), null))){
					return null;
				}
			}
			if( !parameter.getNewPassword().equals(parameter.getConfirmPassword()) ){
				return null;
			}
			user.setPassword(md5.encodePassword(parameter.getNewPassword(), null));
			
			this.getGeneralService().saveOrUpdate(user);
			
			return user;
		} catch (Exception ex) {
			
			ex.printStackTrace();
			return null;
		} 
	}
	

	public boolean validatorLogonNameExists(SystemUserParameter parameter) {
		SystemUser user = parameter.getEntity();
		SearchCriteriaBuilder<SystemUser> searchCriteriaBuilder = new SearchCriteriaBuilder<SystemUser>(SystemUser.class);
		
		searchCriteriaBuilder.addQueryCondition("logonName", RestrictionExpression.EQUALS_OP, user.getLogonName());
		searchCriteriaBuilder.addQueryCondition("enabled", RestrictionExpression.EQUALS_OP, Boolean.TRUE);
		if (user.getId() != null) {
			searchCriteriaBuilder.addQueryCondition("id", RestrictionExpression.NOT_EQUALS_OP, user.getId());
		}
		return getGeneralService().getCount(searchCriteriaBuilder.build()) > 0;
	}

	public SystemUser getSystemUserByLogonName(String logonName) {
		
		SearchCriteriaBuilder<SystemUser> searchCriteriaBuilder = new SearchCriteriaBuilder<SystemUser>(
				SystemUser.class);

		searchCriteriaBuilder.addQueryCondition("logonName",
				RestrictionExpression.EQUALS_OP, logonName);
		searchCriteriaBuilder.addQueryCondition("enabled",
				RestrictionExpression.EQUALS_OP, Boolean.TRUE);

		return getGeneralService().getObjectByCriteria(
				searchCriteriaBuilder.build());
	}

	public SystemUser saveOrUpdate(SystemUserParameter parameter) {
		
		return getCacheParameter(parameter).getUser();
	}

	public CacheParameter getCacheParameter(SystemUserParameter parameter) {
		
		if( !validatorLogonNameExists(parameter) ){
			CacheParameter cacheParameter = new CacheParameter();
			SystemUser entity = parameter.getEntity();
			
			SystemUser user = null;
			
			if ( entity.getId() == null ) {
				
				Md5PasswordEncoder md5 = new Md5PasswordEncoder();
				entity.setPassword(md5.encodePassword(entity.getPassword(), null));
				
				SystemUser existUser = getDeletedUserByLogonName(entity.getLogonName());
				if (existUser != null) {
					BeanUtils.copyProperties(entity, existUser, new String[] { "id" });
					user = existUser;
				} else {
					user = entity;
				}
				
				cacheParameter.setUserLogonName(user.getLogonName());
			} else {
				
				user = (SystemUser) this.getGeneralService().getObjectById(parameter.getEntityClazz(), parameter.getEntity().getId());
				
				cacheParameter.setUserLogonName(user.getLogonName());
				
				user.setRoles(new HashSet<SystemRole>(0));
				
				BeanUtils.copyProperties(entity, user, new String[] { "password", "enabled", "roles", "userRoles" });
			}
			
			user.setRoles(getRolesByIds(user, fitIds(parameter.getRoleIds())));
			
			cacheParameter.setUser(super.saveOrUpdate(user));
			
			return cacheParameter;
		}
		return null;
	}
	
	protected class CacheParameter {
		
		private String userLogonName;
		private SystemUser user;
		
		public CacheParameter() {}

		public String getUserLogonName() {
			return userLogonName;
		}

		public void setUserLogonName(String userLogonName) {
			this.userLogonName = userLogonName;
		}

		public SystemUser getUser() {
			return user;
		}

		public void setUser(SystemUser user) {
			this.user = user;
		}
	}

	private SystemUser getDeletedUserByLogonName(String logonName) {
		
		try {
			
			SearchCriteriaBuilder<SystemUser> searchCriteriaBuilder = new SearchCriteriaBuilder<SystemUser>(SystemUser.class);
			
			searchCriteriaBuilder.addQueryCondition("logonName", RestrictionExpression.EQUALS_OP, logonName);
			searchCriteriaBuilder.addQueryCondition("enabled", RestrictionExpression.EQUALS_OP, Boolean.FALSE);
			
			return (SystemUser) getGeneralService().getObjectByCriteria(searchCriteriaBuilder.build());
		} catch (ObjectNotFoundException ex) {
			return null;
		}
	}

	private Set<SystemRole> getRolesByIds(SystemUser user, String ids) {
		
		SearchCriteriaBuilder<SystemRole> searchCriteriaBuilder = new SearchCriteriaBuilder<SystemRole>(SystemRole.class);
		
		searchCriteriaBuilder.addAdditionalRestrictionSql("ID in(" + ids + ")");
		
		List<SystemRole> roles = getGeneralService().getObjects(searchCriteriaBuilder.build());
		Set<SystemRole> userRoles = new HashSet<SystemRole>();
		for (SystemRole role : roles) {
			userRoles.add(role);
			user.getRoles().add(role);
		}
		return userRoles;
	}

	private Set<SystemRole> getRolesByName(SystemUser user,String roleName){
		
		SearchCriteriaBuilder<SystemRole> searchCriteriaBuilder = new SearchCriteriaBuilder<SystemRole>(SystemRole.class);
		
		searchCriteriaBuilder.addAdditionalRestrictionSql("ROLE_NAME = "+"'"+roleName+"'");
		
		SystemRole role = getGeneralService().getObjectByCriteria(searchCriteriaBuilder.build());
		Set<SystemRole> userRoles = new HashSet<SystemRole>();

		userRoles.add(role);
		user.getRoles().add(role);

		return userRoles;
	}
	
	private String fitIds(Long[] ids) {
		
		StringBuffer sb = new StringBuffer();
		for (Long id : ids) {
			
			sb.append(id).append(",");
		}
		
		return sb.deleteCharAt(sb.length() - 1).toString();
	}

	@Override
	public boolean validateLogonNameAndPassword(String logonName,
			String password) {
		
		return getSystemUserByLogonNameAndPassword(logonName, password) != null;
	}

	public SystemUser getSystemUserByLogonNameAndPassword(String logonName, String password) {
		
		SearchCriteriaBuilder<SystemUser> searchCriteriaBuilder = new SearchCriteriaBuilder<SystemUser>(SystemUser.class);
		searchCriteriaBuilder.addQueryCondition("logonName", RestrictionExpression.EQUALS_OP, logonName);
		searchCriteriaBuilder.addQueryCondition("enabled", RestrictionExpression.EQUALS_OP, Boolean.TRUE);
		Md5PasswordEncoder md5 = new Md5PasswordEncoder();
		searchCriteriaBuilder.addQueryCondition("password", RestrictionExpression.EQUALS_OP, md5.encodePassword(password,null));
		
		try {
			return getGeneralService().getObjectByCriteria(searchCriteriaBuilder.build());
		} catch (ObjectNotFoundException e) {
			return null;
		}
	}

	@Override
	public boolean modifyPassword(String logonName, String originalPassword, String newPassword) {
		
		return modifyPasswordAndReturnSystemUser(logonName, originalPassword, newPassword) != null;
	}

	protected SystemUser modifyPasswordAndReturnSystemUser(String logonName, String originalPassword, String newPassword) {
		
		SystemUser systemUser = getSystemUserByLogonNameAndPassword(logonName, originalPassword);
		if( null != systemUser ){
			
			try {
				Md5PasswordEncoder md5PasswordEncoder = new Md5PasswordEncoder();
				systemUser.setPassword(md5PasswordEncoder.encodePassword(newPassword,null));
				getGeneralService().saveOrUpdate(systemUser);
			} catch (Exception e) {
				return null;
			}
		}
		return systemUser;
	}
}
